package com.hejia.alauda.entity.example;

import com.hejia.alauda.entity.BaseEntity;

import javax.persistence.Table;

import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;


public abstract class Example<T extends BaseEntity>{
	
	private Class<T> entityClass;
	
	protected String orderByClause;
	
	protected String groupByClause;

	protected boolean distinct;

	protected List<Criteria> oredCriteria;
	
	protected String tableName;
	
	protected List<String> columnNames = new ArrayList<String>();
	
	public Example(){
		oredCriteria = new ArrayList<Criteria>();
	}
	
	@SuppressWarnings("unchecked")
	public String getTableName(){
		if(entityClass == null)
			entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];   
		
		Table table = entityClass.getAnnotation(Table.class);
		if (table != null)
			return "`"+table.name()+"`";
		else
			return "`"+entityClass.getSimpleName()+"`";
	}
	
	public void setOrderByClause(String orderByClause) {
		this.orderByClause = orderByClause;
	}

	public String getOrderByClause() {
		return orderByClause;
	}

	
	public String getGroupByClause() {
		return groupByClause;
	}

	public void setGroupByClause(String groupByClause) {
		this.groupByClause = groupByClause;
	}

	public void setDistinct(boolean distinct) {
		this.distinct = distinct;
	}

	public boolean isDistinct() {
		return distinct;
	}

	public List<Criteria> getOredCriteria() {
		return oredCriteria;
	}

	public void or(Criteria criteria) {
		oredCriteria.add(criteria);
	}

	public Criteria or() {
		Criteria criteria = createCriteriaInternal();
		oredCriteria.add(criteria);
		return criteria;
	}

	public Criteria createCriteria() {
		Criteria criteria = createCriteriaInternal();
		if (oredCriteria.size() == 0) {
			oredCriteria.add(criteria);
		}
		return criteria;
	}
	
	protected Criteria getCriteria(){

        return getCriteria(0);
	}
	
	protected Criteria getCriteria(int index){
		if(getOredCriteria().size() > index){
			return getOredCriteria().get(index);
		}else{
			Criteria criteria = new Criteria();
			getOredCriteria().add(criteria);
			return criteria;	
		}
		
	}
	
	public Criteria appendCriterion(String condition){
		return getCriteria().addCriterion(condition);
	}
	
	
	
	public Criteria appendCriterion(String condition, Object value){
		return getCriteria().addCriterion(condition, value);
	}
	
	public Criteria appendCriterion(String condition, Object value1, Object value2){
		return getCriteria().addCriterion(condition,value1 ,value2);
	}


	protected Criteria createCriteriaInternal() {
		Criteria criteria = new Criteria();
		return criteria;
	}

	public void clear() {
		oredCriteria.clear();
		orderByClause = null;
		distinct = false;
	}
	
	protected abstract static class GeneratedCriteria {
		protected List<Criterion> criteria;

		protected GeneratedCriteria() {
			super();
			criteria = new ArrayList<Criterion>();
		}

		public boolean isValid() {
			return criteria.size() > 0;
		}

		public List<Criterion> getAllCriteria() {
			return criteria;
		}

		public List<Criterion> getCriteria() {
			return criteria;
		}
		
		public Criteria addCriterion(String condition) {
			if (condition == null) {
				throw new RuntimeException("Value for condition cannot be null");
			}
			criteria.add(new Criterion(condition));
			return (Criteria)this;
		}
		
		public Criteria addCriterion(String condition, Object value) {
			if (value == null) {
				throw new RuntimeException("Value for " + condition
						+ " cannot be null");
			}
//			if(value instanceof String){
//				value="'"+ (String)value +"'";
//			}
			criteria.add(new Criterion(condition, value));
			return (Criteria)this;
		}

		public Criteria addCriterion(String condition, Object value1,
				Object value2) {
			if (value1 == null || value2 == null) {
				throw new RuntimeException("Between values for " + condition
						+ " cannot be null");
			}
			
//			if(value1 instanceof String){
//				value1="'"+ (String)value1 +"'";
//			}
//			
//			if(value2 instanceof String){
//				value2="'"+ (String)value2 +"'";
//			}
			
			criteria.add(new Criterion(condition, value1, value2));
			return (Criteria)this;
		}

	}
	
	public static class Criteria extends GeneratedCriteria {
		protected Criteria() {
			super();
		}
	}
	
	public static class Criterion {
		private String condition;
		private Object value;
		private Object secondValue;
		private boolean noValue;
		private boolean singleValue;
		private boolean betweenValue;
		private boolean listValue;
		private String typeHandler;

		public String getCondition() {
			return condition;
		}

		public Object getValue() {
			return value;
		}

		public Object getSecondValue() {
			return secondValue;
		}

		public boolean isNoValue() {
			return noValue;
		}

		public boolean isSingleValue() {
			return singleValue;
		}

		public boolean isBetweenValue() {
			return betweenValue;
		}

		public boolean isListValue() {
			return listValue;
		}

		public String getTypeHandler() {
			return typeHandler;
		}

		protected Criterion(String condition) {
			super();
			this.condition = condition;
			this.typeHandler = null;
			this.noValue = true;
		}

		protected Criterion(String condition, Object value, String typeHandler) {
			super();
			this.condition = condition;
			this.value = value;
			this.typeHandler = typeHandler;
			if (value instanceof List<?>) {
				this.listValue = true;
			} else {
				this.singleValue = true;
			}
		}

		protected Criterion(String condition, Object value) {
			this(condition, value, null);
		}

		protected Criterion(String condition, Object value, Object secondValue,
				String typeHandler) {
			super();
			this.condition = condition;
			this.value = value;
			this.secondValue = secondValue;
			this.typeHandler = typeHandler;
			this.betweenValue = true;
		}

		protected Criterion(String condition, Object value, Object secondValue) {
			this(condition, value, secondValue, null);
		}
	}
	
	public void appendColumnName(String... columnName){
		if (columnName != null && columnName.length > 0 && StringUtils.isNoneBlank(columnName)) {
			for (int i = 0; i < columnName.length; i++) {
				this.columnNames.add(columnName[i]);
			}
		}
	}

	public List<String> getColumnNames() {
		return columnNames;
	}

	public void setColumnNames(List<String> columnNames) {
		this.columnNames = columnNames;
	}
}
